SPB Git

spb/llmindex Public

The discriminative, contamination-resistant, fully transparent LLM ranking — updated live.

TypeScript 77.9% TeX 15.2% Python 3.7% SQL 1.4% JavaScript 1.1% Shell 0.5%
11.6 KB · 250 lines tsx
Raw Blame History
1/**2 * llmindex.io — model profile: per-domain scores, sub-metrics, run history3 * Author:  Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * License: Proprietary — © Simon-Pierre Boucher, all rights reserved6 */7import Link from 'next/link';8import { notFound } from 'next/navigation';9import { DemoBanner, ScoreBar, ScoreValue, formatMs, formatUsd } from '@llmindex/ui';10import { ProviderLogo } from '@/components/ProviderLogo';11import { getModelDuels, getModelProfile, getModelResponses } from '@/lib/data';1213export const revalidate = 3600;14export const dynamicParams = true;1516export function generateStaticParams(): Array<{ slug: string[] }> {17  return [];18}1920export default async function ModelPage({ params }: { params: { slug: string[] } }) {21  const slug = params.slug.map(decodeURIComponent).join('/');22  const profile = await getModelProfile(slug);23  if (!profile) notFound();24  const [responses, duels] = await Promise.all([getModelResponses(slug), getModelDuels(slug)]);25  const responseDomains = Object.keys(responses).sort();2627  return (28    <div className="space-y-8">29      <div className="space-y-2">30        <Link href="/" className="text-sm text-zinc-500 hover:text-zinc-900">31          ← Leaderboard32        </Link>33        <h1 className="flex items-center gap-3 text-2xl font-bold text-zinc-900">34          <ProviderLogo provider={profile.provider} size={30} />35          {profile.name}36        </h1>37        <p className="text-sm text-zinc-500">38          {profile.slug} · {profile.provider} · context{' '}39          {profile.contextLength?.toLocaleString() ?? '—'} · in{' '}40          {formatUsd(profile.promptPricePerM)}/1M · out {formatUsd(profile.completionPricePerM)}/1M41        </p>42      </div>4344      {profile.run.kind === 'demo_seed' && <DemoBanner />}4546      {profile.global && (47        <section className="rounded-lg border border-zinc-200 p-5">48          <h2 className="mb-2 text-sm uppercase tracking-wide text-zinc-500">Global Index</h2>49          <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:gap-6">50            <span className="text-4xl font-bold tabular-nums text-emerald-600">51              {profile.global.score}52            </span>53            <div className="flex-1 space-y-1">54              <ScoreBar55                score={profile.global.score}56                scoreLow={profile.global.scoreLow}57                scoreHigh={profile.global.scoreHigh}58              />59              <p className="text-xs text-zinc-500">60                95% CI [{profile.global.scoreLow}–{profile.global.scoreHigh}] · index v61                {profile.run.indexVersion}62              </p>63            </div>64          </div>65        </section>66      )}6768      <section className="space-y-3">69        <h2 className="text-xl font-semibold text-zinc-900">Per-domain scores</h2>70        <div className="overflow-x-auto">71          <table className="w-full min-w-[56rem] text-sm">72            <thead>73              <tr className="border-b border-zinc-200 text-left text-xs uppercase tracking-wide text-zinc-500">74                <th className="py-2 pr-3">Domain</th>75                <th className="py-2 pr-3 text-right">Score (95% CI)</th>76                <th className="w-1/4 py-2 pr-3"></th>77                <th className="py-2 pr-3 text-right">Accuracy (IRT)</th>78                <th className="py-2 pr-3 text-right">Consistency</th>79                <th className="py-2 pr-3 text-right">Calibration</th>80                <th className="py-2 pr-3 text-right">Contam. Δ</th>81                <th className="py-2 pr-3 text-right">p50</th>82                <th className="py-2 pr-3 text-right">$/1k</th>83              </tr>84            </thead>85            <tbody>86              {profile.domains.map((d) => (87                <tr key={d.domain} className="border-b border-zinc-100">88                  <td className="py-2 pr-3 capitalize">89                    <Link90                      href={`/leaderboard/${d.domain}`}91                      className="hover:text-emerald-600"92                    >93                      {d.domain.replaceAll('_', ' ')}94                    </Link>95                  </td>96                  <td className="py-2 pr-3 text-right">97                    <ScoreValue score={d.score} scoreLow={d.scoreLow} scoreHigh={d.scoreHigh} />98                  </td>99                  <td className="py-2 pr-3">100                    <ScoreBar score={d.score} scoreLow={d.scoreLow} scoreHigh={d.scoreHigh} />101                  </td>102                  <td className="py-2 pr-3 text-right tabular-nums text-zinc-600">103                    {d.subMetrics?.accuracy_irt?.toFixed(3) ?? '—'}104                  </td>105                  <td className="py-2 pr-3 text-right tabular-nums text-zinc-600">106                    {d.subMetrics?.consistency?.toFixed(2) ?? '—'}107                  </td>108                  <td className="py-2 pr-3 text-right tabular-nums text-zinc-600">109                    {d.subMetrics?.calibration?.toFixed(2) ?? '—'}110                  </td>111                  <td className="py-2 pr-3 text-right tabular-nums text-zinc-600">112                    {d.subMetrics?.contamination_delta?.toFixed(3) ?? '—'}113                  </td>114                  <td className="py-2 pr-3 text-right tabular-nums text-zinc-600">115                    {formatMs(d.subMetrics?.latency_p50)}116                  </td>117                  <td className="py-2 pr-3 text-right tabular-nums text-zinc-600">118                    {formatUsd(d.subMetrics?.cost_per_1k_items)}119                  </td>120                </tr>121              ))}122            </tbody>123          </table>124        </div>125      </section>126127      {responseDomains.length > 0 && (128        <section className="space-y-3">129          <h2 className="text-xl font-semibold text-zinc-900">Every answer, every test</h2>130          <p className="text-sm text-zinc-500">131            Full transparency: the model&apos;s latest graded answer on every instantiated item of132            the current index version. Answer keys never leave the server; anchor-item prompts are133            withheld to protect the longitudinal subset.134          </p>135          {responseDomains.map((domain) => {136            const rows = responses[domain]!;137            const nCorrect = rows.filter((r) => r.correct === true).length;138            return (139              <details key={domain} className="rounded-xl border border-zinc-200">140                <summary className="cursor-pointer select-none px-4 py-3 text-sm font-medium capitalize text-zinc-800 hover:bg-zinc-50">141                  {domain.replaceAll('_', ' ')}{' '}142                  <span className="ml-2 text-xs tabular-nums text-zinc-500">143                    {nCorrect}/{rows.length} correct144                  </span>145                </summary>146                <div className="max-h-[32rem] space-y-2 overflow-y-auto border-t border-zinc-200 p-3">147                  {rows.map((r, i) => (148                    <div key={i} className="rounded-lg border border-zinc-100 bg-white p-3 text-xs">149                      <div className="flex flex-wrap items-center gap-2">150                        <span151                          className={152                            'rounded px-1.5 py-0.5 font-semibold ' +153                            (r.correct === true154                              ? 'bg-emerald-100 text-emerald-700'155                              : r.correct === false156                                ? 'bg-red-100 text-red-700'157                                : 'bg-zinc-200 text-zinc-600')158                          }159                        >160                          {r.correct === true ? 'correct' : r.correct === false ? 'wrong' : r.error ?? 'unscored'}161                        </span>162                        <span className="text-zinc-500">{r.templateId}</span>163                        {r.isAnchor && <span className="rounded bg-amber-100 px-1.5 py-0.5 text-amber-700">anchor</span>}164                        <span className="ml-auto tabular-nums text-zinc-500">165                          conf {r.confidence != null ? Math.round(r.confidence * 100) + '%' : '—'} ·{' '}166                          {formatMs(r.latencyMs)} · {formatUsd(r.costUsd)} · {r.tokensOut ?? '—'} tok167                        </span>168                      </div>169                      {r.prompt && (170                        <details className="mt-2">171                          <summary className="cursor-pointer text-zinc-500">question</summary>172                          <pre className="mt-1 max-h-48 overflow-auto whitespace-pre-wrap rounded bg-zinc-100 p-2 text-[11px] text-zinc-600">173                            {r.prompt}174                          </pre>175                        </details>176                      )}177                      <div className="mt-2">178                        <span className="text-zinc-500">model answer: </span>179                        <code className="break-all text-zinc-800">{r.answer ?? '(none extracted)'}</code>180                      </div>181                    </div>182                  ))}183                </div>184              </details>185            );186          })}187        </section>188      )}189190      {duels.length > 0 && (191        <section className="space-y-3">192          <h2 className="text-xl font-semibold text-zinc-900">Judge-rated duels</h2>193          <p className="text-sm text-zinc-500">194            Pairwise duels (writing, safety, SVG logo design) rated by a cross-provider judge195            panel with recorded position swaps.196          </p>197          <div className="space-y-2">198            {duels.map((d, i) => (199              <details key={i} className="rounded-xl border border-zinc-200">200                <summary className="cursor-pointer select-none px-4 py-3 text-sm hover:bg-zinc-50">201                  <span202                    className={203                      'mr-2 rounded px-1.5 py-0.5 text-xs font-semibold ' +204                      (d.outcome === 'win'205                        ? 'bg-emerald-100 text-emerald-700'206                        : d.outcome === 'loss'207                          ? 'bg-red-100 text-red-700'208                          : 'bg-zinc-200 text-zinc-600')209                    }210                  >211                    {d.outcome}212                  </span>213                  <span className="capitalize text-zinc-700">{d.domain.replaceAll('_', ' ')}</span>214                  <span className="text-zinc-500"> vs {d.opponent} · judge {d.judge}</span>215                  {d.positionSwapped && <span className="ml-1 text-xs text-zinc-400">(positions swapped)</span>}216                </summary>217                <div className="space-y-2 border-t border-zinc-200 p-3 text-xs">218                  <div>219                    <span className="text-zinc-500">task: </span>220                    <span className="text-zinc-700">{d.prompt.slice(0, 400)}</span>221                  </div>222                  {d.myResponseExcerpt && (223                    <pre className="max-h-48 overflow-auto whitespace-pre-wrap rounded bg-zinc-100 p-2 text-[11px] text-zinc-600">224                      {d.myResponseExcerpt}225                    </pre>226                  )}227                </div>228              </details>229            ))}230          </div>231        </section>232      )}233234      <section className="space-y-3">235        <h2 className="text-xl font-semibold text-zinc-900">Run history</h2>236        <ul className="space-y-1 text-sm text-zinc-600">237          {profile.runHistory.map((h) => (238            <li key={h.runId} className="flex gap-4">239              <span className="tabular-nums">{new Date(h.createdAt).toISOString().slice(0, 10)}</span>240              <span>v{h.indexVersion}</span>241              <span className="text-zinc-500">{h.kind}</span>242              <span className="tabular-nums text-zinc-800">{h.score ?? '—'}</span>243            </li>244          ))}245        </ul>246      </section>247    </div>248  );249}250